package com.rmv.ums.configuration;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.XPP3Reader;
import org.xmlpull.v1.XmlPullParserException;

import com.rmv.ums.FrontEndServlet;
import com.rmv.ums.configuration.model.ConfigurableNodeException;
import com.rmv.ums.configuration.model.ConfigurableNodeFactory;
import com.rmv.ums.request.Request;
import com.rmv.ums.response.Response;

public class RequestsLoader {

	private static final Logger logger = Logger.getLogger(FrontEndServlet.class);

	// fields
	private XPP3Reader reader = new XPP3Reader();
	private URL url;
	private Map responses;
	private Set requests;

	public RequestsLoader(URL url) {
		this.url = url;
		load();
	}

	public Map getResponses() {
		return responses;
	}

	public Set getRequests() {
		return requests;
	}

	private void load() {
		String path = url.getPath();
		try {

			if (logger.isDebugEnabled())
				logger.debug("main request configuration file:" + path);

			// clear all the old watchdogs
			responses = new HashMap();
			requests = new HashSet();

			// loadFile
			loadFile(path);

			if (logger.isDebugEnabled())
				logger.debug("loaded the requests configuration from:" + path);

		} catch (FileNotFoundException e) {
			throw new RuntimeException("error loading requests configuration. file " + path + "not found", e);
		} catch (DocumentException e) {
			throw new RuntimeException("error parsing requests configuration file " + path, e);
		} catch (IOException e) {
			throw new RuntimeException("error reading requests configuration file " + path, e);
		} catch (XmlPullParserException e) {
			throw new RuntimeException("error parsing requests configuration file " + path, e);
		}
	}

	private void loadFile(String filename) throws FileNotFoundException, DocumentException, IOException, XmlPullParserException {

		if (logger.isDebugEnabled())
			logger.debug("loading request configuration file:" + filename);

		Document document = reader.read(new FileReader(filename));

		// load include files
		List includeNodes = document.selectNodes("configuration/include");
		for (Iterator iter = includeNodes.iterator(); iter.hasNext();) {
			Element includeElement = (Element) iter.next();
			String includeFilename = includeElement.attribute("path").getStringValue();
			if (includeFilename.indexOf(File.separatorChar) == -1)
				includeFilename = getBasePath(filename) + includeFilename;
			if (logger.isDebugEnabled())
				logger.debug("included configuration file found:" + includeFilename);
			try {
				loadFile(includeFilename);
			} catch (Exception e) {
				logger.warn("error loading included file - skipping it :" + includeFilename, e);
			}
		}

		// load responses
		List responseNodes = document.selectNodes("configuration/response");
		for (Iterator iter = responseNodes.iterator(); iter.hasNext();) {
			Element responseElement = (Element) iter.next();
			String id = responseElement.attribute("id").getStringValue();
			if (StringUtils.isBlank(id)) {
				logger.warn("standalone response without id - skipping it. response:" + responseElement.asXML());
				continue;
			}

			try {
				Response response = (Response) ConfigurableNodeFactory.get(Configuration.RESPONSE, responseElement);
				responses.put(id, response);
			} catch (ConfigurableNodeException e) {
				logger.warn("response error - skipping it. request:" + responseElement.asXML(), e);
				continue;
			}
		}

		// load requests
		List requestNodes = document.selectNodes("configuration/request");
		for (Iterator iter = requestNodes.iterator(); iter.hasNext();) {
			Element requestElement = (Element) iter.next();

			try {
				Request request = (Request) ConfigurableNodeFactory.get(Configuration.REQUEST, requestElement);
				requests.add(request);
			} catch (ConfigurableNodeException e) {
				logger.warn("request error - skipping it. request:" + requestElement.asXML(), e);
				continue;
			}
		}
	}

	private String getBasePath(String filename) {
		return filename.substring(0, filename.lastIndexOf(File.separatorChar));
	}
}
